#include <stdlib.h>
#include <string.h>
#include <directfb.h>

#include "dtk_types.h"
#include "dtk_debug.h"
#include "dtk_priv.h"
#include "dtk_actor.h"
#include "dtk_single.h"
#include "dtk_stage.h"

const DString DTK_TYPE_STAGE = "DTKStage";

typedef struct _update
{
    DInt      pending;
    DRegion   region;
}UPDATES;

struct _stage_priv
{
    DBoolean      need_paint;
    long long       first_paint_time;
    DRegion       paint_bounds;

    UPDATES         update;
};

static DTKStageDescription     g_desc;

DBoolean stage_update (DTKActor* self, DRegion* region, DBoolean flag)
{
    DTKStage* stage = (DTKStage*)self;
    DRegion update;

    DTK_TYPE_ASSERT (self, DTK_TYPE_STAGE);

    if (NULL == region)
    {
        dtk_actor_get_region (self, &update);
        region = &update;
    }

    dtk_region_add(&stage->priv->update.region,
        &stage->priv->update.region,
        region);

    dtk_region_dump(__func__, &stage->priv->update.region);

    stage->priv->update.pending = DTK_TRUE;

    dtk_event_wakeup();
    return DTK_TRUE;
}

IDirectFBSurface* stage_get_surface(DTKActor* self)
{
    DTKStage* stage = (DTKStage*)self;
    IDirectFBSurface* surface;
    DFBRectangle dfb_rect;
    DFBResult ret;

    DTK_TYPE_ASSERT (self, DTK_TYPE_STAGE);

    if (self->surface == NULL)
    {
        self->surface = dtk_stage_window_get_surface (stage->stage_window);
        if (self->surface == NULL)
        {
            return NULL;
        }
    }
    
    return self->surface;
}

static void stage_show(DTKActor* self)
{
    DTKStage* stage = (DTKStage*) self;

    DTK_TYPE_ASSERT (self, DTK_TYPE_STAGE);

    dtk_actor_update(self, NULL, DTK_FALSE);
    dtk_stage_window_show(stage->stage_window, DTK_ACTOR(stage)->opacity);

    return;
}

static void stage_hide(DTKActor* self)
{
    DTKStage* stage = (DTKActor*)self;

    DTK_TYPE_ASSERT (self, DTK_TYPE_STAGE);
    dtk_stage_window_show(stage->stage_window, 0);
    return;
}

void dtk_stage_get_default_description(DTKStageDescription* desc)
{    
    if (desc == NULL)
    {
        return;
    }
    
    desc->fullscreen = DTK_FALSE;
    desc->title = "default window";
    desc->x = 0;
    desc->y = 0;
    dtk_get_screen_size(&desc->width, &desc->height);
    
    return;
}

void stage_release (DTKActor* self)
{
    DTKStage* stage = (DTKStage*) self;

    DTK_TYPE_ASSERT(self, DTK_TYPE_STAGE);

    if (stage->stage_window)
    {
        dtk_stage_window_destroy (stage->stage_window);
    }

    if (stage->title)
    {
        free (stage->title);
    }

    dtk_set_stage (NULL);

    return;
}

DTKActor* dtk_stage_new(DTKStageDescription* desc)
{
    DTKStage*               stage;
    DTKActor*               actor;
    DTKActorCallback*       funcs;
    DTKContainer*           content;
    DTKLayout*              layout;

    if (DTK_FALSE == dtk_is_initialized())
    {
        return NULL;
    }

    if (NULL == desc)
    {
        dtk_stage_get_default_description (&g_desc);
        desc = &g_desc;
    }

    
    actor = dtk_single_init (sizeof(DTKStage) + sizeof (DTKStagePriv),
                DTK_TYPE_STAGE, DACAPS_HASCONTENT);

    layout = dtk_single_layout_new (actor);
    dtk_actor_set_layout (actor, layout);

    stage = (DTKStage*) actor;
    stage->priv = (DTKStagePriv*)(stage + 1);
            
    dtk_actor_set_position (actor, desc->x, desc->y);
    dtk_actor_set_default_size (actor, desc->width, desc->height);
    dtk_stage_set_title (stage, desc->title);

    stage->stage_window = dtk_stage_window_create (desc);

    dtk_stage_window_set_property(stage->stage_window,
                                    "stage",
                                    stage,
                                    NULL);

    funcs = DTK_ACTOR_CALLBACK(actor);
    funcs->show = stage_show;
    funcs->hide = stage_hide;
    funcs->get_surface = stage_get_surface;
    funcs->release = stage_release;

    dtk_set_stage(actor);
    return actor;
}

void dtk_stage_set_title (DTKActor* self, const DString title)
{
    DTKStage* stage = (DTKStage*) self;

    DTK_TYPE_ASSERT (self, DTK_TYPE_STAGE);
    if (title == NULL)
    {
        return;
    }

    if (stage->title)
    {
        free (stage->title);
    }
    stage->title = strdup(title);
    return;
}

DString dtk_stage_get_title (DTKActor* self)
{
    DTKStage* stage = (DTKStage*) self;
    DTK_TYPE_ASSERT (self, DTK_TYPE_STAGE);

    return stage->title;
}

DBoolean dtk_stage_draw(DTKActor* self)
{
    DTKStage* stage = (DTKStage*) self;
    DTKGC gc;
    DTK_TYPE_ASSERT (self, DTK_TYPE_STAGE);

    gc.surface = dtk_stage_window_get_surface(stage->stage_window);
    dtk_layout_draw (self->layout, &gc, NULL);
    gc.surface->Flip (gc.surface, NULL, DSFLIP_NONE);

    return DTK_TRUE;
}

